#include "leam-basic-socket-test.hh"
#include <QLineEdit>
#include <QPushButton>
#include <QDialogButtonBox>
#include <QLabel>
#include <QTcpSocket>
#include <QGridLayout>
#include <QMessageBox>
#include <iostream>

using namespace licada;
using namespace std;

namespace leam
{
    BasicSocketTestClient::BasicSocketTestClient(QWidget *parent, unsigned _port ) 
	: QDialog(parent)
    {
	messageLineEdit = new QLineEdit("be pepper too");
	sendMessageButton = new QPushButton(tr("Send"));
	sendMessageButton->setDefault(true);
	statusLabel = new QLabel(tr("Send Message"));
	quitButton = new QPushButton(tr("Quit"));

	buttonBox = new QDialogButtonBox;
	buttonBox->addButton(sendMessageButton, QDialogButtonBox::ActionRole);
	buttonBox->addButton(quitButton, QDialogButtonBox::RejectRole);

	tcpSocket = new QTcpSocket(this);
	tcpSocket->connectToHost("Localhost", _port );
	if ( !tcpSocket->waitForConnected( 5000 ) )
	    throw std::runtime_error("Failed to connect appropriately");
	inStream.setup( tcpSocket );
	outStream.setup( tcpSocket );
	leamStream.setup( &inStream, &outStream, this );
	connect(sendMessageButton, SIGNAL(clicked()),
		this, SLOT(sendMessage()));
	connect(quitButton, SIGNAL(clicked()), this, SLOT(close()));
	connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(readNext()));
	connect(tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)),
		this, SLOT(displayError(QAbstractSocket::SocketError)));

	QGridLayout *mainLayout = new QGridLayout;
	mainLayout->addWidget(messageLineEdit, 0, 0);
	mainLayout->addWidget(statusLabel, 2, 0, 1, 2);
	mainLayout->addWidget(buttonBox, 3, 0, 1, 2);
	setLayout(mainLayout);

	setWindowTitle(tr("Leam Client"));
    }
    BasicSocketTestClient::~BasicSocketTestClient()
    {
	if ( tcpSocket )
	    tcpSocket->close();
	delete tcpSocket;
	tcpSocket = NULL;
    }

    void BasicSocketTestClient::handleData( TMessageId msg
					    , LeamDataInStream& data )
    {
	//assume message is just a string
	TDataVector tempVector;
	tempVector.resize( data.getRemaining() );
	data >> tempVector;
	tempVector.push_back( 0 );
	const char* dataBuf = (char*)&(*tempVector.begin());
	cout << "Received message " << msg << ": " << dataBuf << endl;
	statusLabel->setText( dataBuf );
    }
    void BasicSocketTestClient::handleError( TMessageId 
					     , const std::string& 
					     , LeamDataInStream& )
    {
    }
    void BasicSocketTestClient::handleAck( TMessageId msg )
    {
	cout << "Received ack: " << msg << endl;
    }
    void BasicSocketTestClient::handleFin( TMessageId msg )
    {
	cout << "Received fin: " << msg << endl;
    }
    void BasicSocketTestClient::handleClose()
    {
	cout << "Connection closed" << endl;
	inStream.setup( NULL );
	outStream.setup( NULL );
    }

    void BasicSocketTestClient::sendMessage()
    {
	QString sendData = messageLineEdit->text();
	cout << "Trying to send a message" << endl;
	TBeginMessageReturn result = leamStream.beginSendMessage( sendData.size() );
	cout << "sending message " << result.first << endl;
	licada::TDataVector dataVector;
	for (unsigned index = 0; index < (unsigned)sendData.size(); ++index )
	    dataVector.push_back( (uint8) sendData[index].toAscii() );
	(*result.second) << dataVector;
    }
    void BasicSocketTestClient::readNext()
    {
	while (tcpSocket->bytesAvailable())
	    leamStream.readNext();
    }
    void BasicSocketTestClient::displayError(
	QAbstractSocket::SocketError socketError)
    {
	//not worried about this one.
	switch (socketError) {
	case QAbstractSocket::RemoteHostClosedError:
	    break;
	case QAbstractSocket::HostNotFoundError:
	    QMessageBox::information(this, tr("Fortune Client"),
				     tr("The host was not found. Please check the "
					"host name and port settings."));
	    break;
	case QAbstractSocket::ConnectionRefusedError:
	    QMessageBox::information(this, tr("Fortune Client"),
				     tr("The connection was refused by the peer. "
					"Make sure the fortune server is running, "
					"and check that the host name and port "
					"settings are correct."));
	    break;
	default:
	    QMessageBox::information(this, tr("Fortune Client"),
				     tr("The following error occurred: %1.")
				     .arg(tcpSocket->errorString()));
	}
    }
}

int main( int c, char** v )
{
    using namespace leam;
    int port = 7000;
    if ( c > 1 )
	port = atol( v[1] );
    QApplication app(c, v);

    try {
	BasicSocketTestClient client(NULL, port );
	client.show();
	return client.exec();
    }
    catch( licada::LicadaError& err )
    {
	cout << err.getStackTrace() << endl;
    }
}
